
package com.shiku.commons.thread.pool;


import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;


public class SynThreadPoolExecutor
        extends ThreadPoolExecutor {
    private String name = null;


    public SynThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, BlockingQueue<Runnable> runnableQueue, ThreadFactory threadFactory, String name) {

        super(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, runnableQueue, threadFactory);

        this.name = name;

    }


    private boolean checkBeforeExecute(Runnable runnable) {

        if (runnable instanceof AbstractSynRunnable) {

            AbstractSynRunnable synRunnable = (AbstractSynRunnable) runnable;


            if (synRunnable.isExecuted()) {

                return false;

            }


            ReadWriteLock runningLock = synRunnable.runningLock();

            Lock writeLock = runningLock.writeLock();

            boolean tryLock = writeLock.tryLock();


            try {

                if (tryLock) {

                    if (synRunnable.isExecuted()) {

                        return false;

                    }

                    synRunnable.executeCount.incrementAndGet();


                    synRunnable.setExecuted(true);

                }


                return tryLock;

            } finally {

                if (tryLock) {

                    writeLock.unlock();

                }

            }

        }

        return true;

    }


    @Override
    public void execute(Runnable runnable) {

        if (checkBeforeExecute(runnable)) {

            execute1(runnable);

        }

    }


    private void execute1(Runnable runnable) {

        super.execute(runnable);

    }


    public String getName() {

        return this.name;

    }


    public void setName(String name) {

        this.name = name;

    }


    @Override
    public <R> Future<R> submit(Runnable runnable, R result) {

        if (checkBeforeExecute(runnable)) {

            Future<R> ret = super.submit(runnable, result);

            return ret;

        }

        return null;

    }

}


